package com.liyuxiang.graph.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.liyuxiang.graph.context.DiagnosisContext;
import com.liyuxiang.graph.memory.SpringAiRedisChatMemory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Optional;
import java.util.Set;

/**
 * 智能问诊上下文管理服务
 * 基于Redis实现问诊过程中的状态持久化和管理
 */
@Service
public class DiagnosisContextService {
    
    private static final Logger logger = LoggerFactory.getLogger(DiagnosisContextService.class);
    
    // Redis key前缀
    private static final String CONTEXT_KEY_PREFIX = "diagnosis:context:";
    // 上下文过期时间：24小时
    private static final Duration CONTEXT_EXPIRY = Duration.ofHours(1);
    
    private final StringRedisTemplate redisTemplate;
    private final ObjectMapper objectMapper;
    private final SpringAiRedisChatMemory chatMemory;
    
    public DiagnosisContextService(StringRedisTemplate redisTemplate, SpringAiRedisChatMemory chatMemory) {
        this.redisTemplate = redisTemplate;
        this.chatMemory = chatMemory;
        this.objectMapper = new ObjectMapper();
        // 注册Java 8时间模块
        this.objectMapper.registerModule(new JavaTimeModule());
    }
    
    /**
     * 保存或更新诊断上下文
     */
    public void saveContext(DiagnosisContext context) {
        try {
            String key = generateKey(context.getThreadId());
            context.updateTimestamp();
            String json = objectMapper.writeValueAsString(context);
            
            redisTemplate.opsForValue().set(key, json, CONTEXT_EXPIRY);
            
            logger.info("已保存诊断上下文 - threadId: {}, userId: {}, 问题轮次: {}", 
                    context.getThreadId(), context.getUserId(), context.getQuestionCount());
            
        } catch (JsonProcessingException e) {
            logger.error("序列化诊断上下文失败 - threadId: {}", context.getThreadId(), e);
            throw new RuntimeException("保存诊断上下文失败", e);
        }
    }
    
    /**
     * 获取诊断上下文
     */
    public Optional<DiagnosisContext> getContext(String threadId) {
        try {
            String key = generateKey(threadId);
            String json = redisTemplate.opsForValue().get(key);
            
            if (json == null || json.isEmpty()) {
                logger.debug("诊断上下文不存在 - threadId: {}", threadId);
                return Optional.empty();
            }
            
            DiagnosisContext context = objectMapper.readValue(json, DiagnosisContext.class);
            logger.info("已加载诊断上下文 - threadId: {}, userId: {}, 问题轮次: {}", 
                    context.getThreadId(), context.getUserId(), context.getQuestionCount());
            
            return Optional.of(context);
            
        } catch (JsonProcessingException e) {
            logger.error("反序列化诊断上下文失败 - threadId: {}", threadId, e);
            return Optional.empty();
        }
    }
    
    /**
     * 获取或创建诊断上下文
     */
    public DiagnosisContext getOrCreateContext(String userId, String threadId) {
        return getContext(threadId)
                .orElseGet(() -> {
                    DiagnosisContext newContext = new DiagnosisContext(userId, threadId);
                    logger.info("创建新的诊断上下文 - threadId: {}, userId: {}", threadId, userId);
                    return newContext;
                });
    }
    
    /**
     * 删除诊断上下文
     * 同时清理ChatMemory，确保对话历史完全删除
     */
    public void deleteContext(String threadId) {
        String key = generateKey(threadId);
        Boolean deleted = redisTemplate.delete(key);
        
        // 同时清理ChatMemory中的对话历史
        try {
            chatMemory.clear(threadId);
            logger.info("已清理ChatMemory对话历史 - threadId: {}", threadId);
        } catch (Exception e) {
            logger.error("清理ChatMemory对话历史失败 - threadId: {}, 错误: {}", threadId, e.getMessage(), e);
        }
        
        if (Boolean.TRUE.equals(deleted)) {
            logger.info("已删除诊断上下文 - threadId: {}", threadId);
        } else {
            logger.warn("删除诊断上下文失败或不存在 - threadId: {}", threadId);
        }
    }
    
    /**
     * 检查上下文是否存在
     */
    public boolean existsContext(String threadId) {
        String key = generateKey(threadId);
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
    
    /**
     * 延长上下文过期时间
     */
    public void extendContextExpiry(String threadId) {
        String key = generateKey(threadId);
        redisTemplate.expire(key, CONTEXT_EXPIRY);
        logger.debug("已延长诊断上下文过期时间 - threadId: {}", threadId);
    }
    
    /**
     * 更新上下文中的用户查询
     */
    public void updateQuery(String threadId, String query) {
        getContext(threadId).ifPresent(context -> {
            context.addConversationHistory("用户: " + query);
            saveContext(context);
        });
    }
    
    /**
     * 更新上下文中的助手回复
     */
    public void updateResponse(String threadId, String response) {
        getContext(threadId).ifPresent(context -> {
            context.addConversationHistory("助手: " + response);
            context.setLastResponse(response);
            saveContext(context);
        });
    }
    
    /**
     * 更新意图识别结果
     */
    public void updateIntentType(String threadId, String intentType) {
        getContext(threadId).ifPresent(context -> {
            context.setIntentType(intentType);
            saveContext(context);
        });
    }
    
    /**
     * 添加症状信息
     */
    public void addSymptom(String threadId, String key, Object value) {
        getContext(threadId).ifPresent(context -> {
            context.addSymptom(key, value);
            saveContext(context);
        });
    }
    
    /**
     * 增加问题计数
     */
    public void incrementQuestionCount(String threadId) {
        getContext(threadId).ifPresent(context -> {
            context.incrementQuestionCount();
            saveContext(context);
        });
    }
    
    /**
     * 设置问诊完成状态
     */
    public void markCompleted(String threadId, String department) {
        getContext(threadId).ifPresent(context -> {
            context.setIsCompleted(true);
            context.setShouldContinue(false);
            context.setRecommendedDepartment(department);
            saveContext(context);
        });
    }
    
    /**
     * 完全清理会话 - 包括诊断上下文、ChatMemory和AI缓存
     */
    public void clearCompleteSession(String threadId) {
        logger.info("开始完全清理会话 - threadId: {}", threadId);
        
        try {
            // 1. 清理诊断上下文
            String key = generateKey(threadId);
            Boolean contextDeleted = redisTemplate.delete(key);
            logger.info("清理诊断上下文: {} - {}", key, contextDeleted);
            
            // 2. 清理ChatMemory - 多种可能的key格式
            String[] chatMemoryKeys = {
                "ai-chat:memory:" + threadId,
                "ai-chat:memory:session_" + threadId,
                "chat:memory:" + threadId
            };
            
            for (String chatKey : chatMemoryKeys) {
                Boolean deleted = redisTemplate.delete(chatKey);
                if (Boolean.TRUE.equals(deleted)) {
                    logger.info("成功清理ChatMemory键: {}", chatKey);
                }
            }
            
            // 调用ChatMemory的clear方法
            chatMemory.clear(threadId);
            logger.info("调用ChatMemory.clear(“{}”)", threadId);
            
            // 3. 清理AI缓存 - 提取userId进行清理
            String userId = extractUserIdFromThreadId(threadId);
            if (userId != null && !userId.isEmpty()) {
                clearAiCacheForUser(userId);
                logger.info("清理AI缓存 - 用户ID: {}", userId);
            }
            
            // 4. 清理所有相关的Redis键（使用模式匹配）
            clearRelatedRedisKeys(threadId);
            
            logger.info("完全清理会话完成 - threadId: {}", threadId);
            
        } catch (Exception e) {
            logger.error("完全清理会话失败 - threadId: {}, 错误: {}", threadId, e.getMessage(), e);
        }
    }
    
    /**
     * 从 threadId 中提取 userId
     */
    private String extractUserIdFromThreadId(String threadId) {
        // 假设 threadId 格式为 "session_userId" 或直接是 userId
        if (threadId.startsWith("session_")) {
            return threadId.substring(8); // 移除 "session_" 前缀
        }
        // 如果是纯数字或简单字符串，就当做 userId
        return threadId;
    }
    
    /**
     * 清理用户的AI缓存
     */
    private void clearAiCacheForUser(String userId) {
        try {
            String[] cachePatterns = {
                "ai:intent:" + userId + ":*",
                "ai:conversation:" + userId + ":*"
            };
            
            for (String pattern : cachePatterns) {
                Set<String> keys = redisTemplate.keys(pattern);
                if (keys != null && !keys.isEmpty()) {
                    redisTemplate.delete(keys);
                    logger.info("清理AI缓存键: {} 个键", keys.size());
                }
            }
        } catch (Exception e) {
            logger.error("清理AI缓存失败 - 用户ID: {}, 错误: {}", userId, e.getMessage());
        }
    }
    
    /**
     * 清理所有相关的Redis键
     */
    private void clearRelatedRedisKeys(String threadId) {
        try {
            String[] patterns = {
                "*:" + threadId,
                "*:" + threadId + ":*",
                "*:session_" + threadId + ":*"
            };
            
            for (String pattern : patterns) {
                Set<String> keys = redisTemplate.keys(pattern);
                if (keys != null && !keys.isEmpty()) {
                    redisTemplate.delete(keys);
                    logger.info("清理相关Redis键 (模式: {}): {} 个键", pattern, keys.size());
                }
            }
        } catch (Exception e) {
            logger.error("清理相关Redis键失败 - threadId: {}, 错误: {}", threadId, e.getMessage());
        }
    }
    
    /**
     * 生成Redis key
     */
    private String generateKey(String threadId) {
        return CONTEXT_KEY_PREFIX + threadId;
    }
}